package dk.pun.dums.shared.character;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.jdo.annotations.EmbeddedOnly;
import javax.jdo.annotations.PersistenceCapable;

@SuppressWarnings("serial")
@PersistenceCapable @EmbeddedOnly
public class CharacterDisciplines implements Serializable {

	private Set<Discipline> clanDisciplines;
	private Set<Discipline> characterDisciplines;
	
	public CharacterDisciplines() {
		this.characterDisciplines = new HashSet<Discipline>();
		this.clanDisciplines = new HashSet<Discipline>();
	}

	public Set<Discipline> getClanDisciplines() {
		return this.clanDisciplines;
	}
	
	public void setClanDisciplines(final Clan clan) {
		if (clan == null) {
			throw new IllegalArgumentException("Clan must not be null.");
		} else {
			this.clanDisciplines.clear();
			DisciplineType[] disciplineTypes = clan.getDisciplineTypes();
			for (DisciplineType disciplineType : disciplineTypes) {
				this.clanDisciplines.add(disciplineType.getDisciplines()[0]);
			}
		}
	}
	
	public Set<Discipline> getCharacterDisciplines() {
		return this.characterDisciplines;
	}
	
	public boolean addCharacterDiscipline(final Discipline discipline, final CharacterData characterData) {
		if (discipline == null) {
			throw new IllegalArgumentException("Discipline must not be null.");
		}
		boolean result;
		if (characterData.canAddDiscipline(discipline)) {
			result = this.characterDisciplines.add(discipline);
		} else {
			result = false;
		}
		return result;
	}
	
	public boolean removeCharacterDiscipline(final Discipline discipline) {
		if (discipline == null) {
			throw new IllegalArgumentException("Discipline must not be null.");
		}
		return this.characterDisciplines.remove(discipline);
	}
	
	public boolean isCharacterDiscipline(final Discipline discipline) {
		return (discipline != null && (this.isClanDiscipline(discipline) || this.characterDisciplines.contains(discipline)));
	}
	
	public boolean isClanDiscipline(final Discipline discipline) {
		return (discipline != null && this.clanDisciplines.contains(discipline));
	}
	
	public Set<Discipline> getAvailableDisciplines(final CharacterData characterData) {
		Set<Discipline> result = new HashSet<Discipline>();
		for (DisciplineType type : DisciplineType.values()) {
			for (Discipline discipline : type.getDisciplines()) {
				int levelAdded = 0;
				if (!this.isClanDiscipline(discipline) && !this.isCharacterDiscipline(discipline) && characterData.canAddDiscipline(discipline)) {
					int level = discipline.getLevel();
					if (level == 1 && (levelAdded == 1 || levelAdded == 0)) {
						result.add(discipline);
						levelAdded = 1;
					} else if (level == 2 && (levelAdded == 2 || levelAdded == 0)) {
						result.add(discipline);
						levelAdded = 2;
					} else if (level == 3 && (levelAdded == 3 || levelAdded == 0)) {
						result.add(discipline);
						levelAdded = 3;
					}
				}
			}
		}
		return result;
	}
	
	public int getUsedPoints() {
		int result = 0;
		for (Discipline discipline : this.characterDisciplines) {
			result += discipline.getLevel();
		}
		return result;
	}
}
